Frigjør kraften i GraphQL Føderasjon med Skjemasammenslåing. Lær hvordan du bygger et enhetlig GraphQL API fra flere tjenester for å forbedre skalerbarhet og vedlikeholdbarhet.
GraphQL Føderasjon: Skjemasammenslåing – en omfattende guide
I det stadig utviklende landskapet for moderne applikasjonsutvikling har behovet for skalerbare og vedlikeholdbare arkitekturer blitt avgjørende. Mikrotjenester, med sin iboende modularitet og uavhengige distribuerbarhet, har blitt en populær løsning. Likevel kan håndtering av mange mikrotjenester introdusere kompleksitet, spesielt når det gjelder å eksponere et enhetlig API for klientapplikasjoner. Det er her GraphQL Føderasjon, og spesifikt Skjemasammenslåing, kommer inn i bildet.
Hva er GraphQL Føderasjon?
GraphQL Føderasjon er en kraftig arkitektur som lar deg bygge ett enkelt, enhetlig GraphQL API fra flere underliggende GraphQL-tjenester (som ofte representerer mikrotjenester). Det gjør det mulig for utviklere å spørre etter data på tvers av forskjellige tjenester som om det var én enkelt graf, noe som forenkler klientopplevelsen og reduserer behovet for kompleks orkestreringslogikk på klientsiden.
Det finnes to primære tilnærminger til GraphQL Føderasjon:
- Skjemasammenslåing (Schema Stitching): Dette innebærer å kombinere flere GraphQL-skjemaer til ett enkelt, enhetlig skjema på gateway-laget. Det er en tidligere tilnærming og er avhengig av biblioteker for å håndtere skjemakombinasjonen og spørringsdelegeringen.
- Apollo Federation: Dette er en nyere og mer robust tilnærming som bruker et deklarativt skjemaspråk og en dedikert spørringsplanlegger for å håndtere føderasjonsprosessen. Den tilbyr avanserte funksjoner som typeutvidelser, nøkkeldirektiver og distribuert sporing.
Denne artikkelen fokuserer på Skjemasammenslåing, og utforsker konseptene, fordelene, begrensningene og den praktiske implementeringen.
Forstå Skjemasammenslåing
Skjemasammenslåing er prosessen med å flette flere GraphQL-skjemaer til ett enkelt, sammenhengende skjema. Dette enhetlige skjemaet fungerer som en fasade og skjuler kompleksiteten til de underliggende tjenestene for klienten. Når en klient sender en forespørsel til det sammenslåtte skjemaet, ruter gatewayen intelligent forespørselen til den eller de aktuelle underliggende tjenestene, henter dataene og kombinerer resultatene før de returneres til klienten.
Tenk på det slik: Du har flere restauranter (tjenester) som hver spesialiserer seg på ulike kjøkken. Skjemasammenslåing er som en universell meny som kombinerer alle rettene fra hver restaurant. Når en kunde (klient) bestiller fra den universelle menyen, blir bestillingen intelligent rutet til de riktige restaurantkjøkkenene, maten blir tilberedt, og deretter kombinert til én enkelt levering for kunden.
Nøkkelkonsepter i Skjemasammenslåing
- Fjerntliggende skjemaer (Remote Schemas): Dette er de individuelle GraphQL-skjemaene for hver underliggende tjeneste. Hver tjeneste eksponerer sitt eget skjema, som definerer dataene og operasjonene den tilbyr.
- Gateway: Gatewayen er den sentrale komponenten som er ansvarlig for å slå sammen de fjerntliggende skjemaene og eksponere det enhetlige skjemaet for klienten. Den mottar klientforespørsler, ruter dem til de aktuelle tjenestene og kombinerer resultatene.
- Skjemafletting (Schema Merging): Dette er prosessen med å kombinere de fjerntliggende skjemaene til ett enkelt skjema. Dette innebærer ofte å gi nye navn til typer og felt for å unngå konflikter og å definere relasjoner mellom typer på tvers av forskjellige skjemaer.
- Spørringsdelegering (Query Delegation): Når en klient sender en forespørsel til det sammenslåtte skjemaet, må gatewayen delegere forespørselen til den eller de aktuelle underliggende tjenestene for å hente dataene. Dette innebærer å oversette klientens spørring til en spørring som kan forstås av den fjerntliggende tjenesten.
- Resultataggregering (Result Aggregation): Etter at gatewayen har hentet data fra de underliggende tjenestene, må den kombinere resultatene til ett enkelt svar som kan returneres til klienten. Dette innebærer ofte å transformere dataene slik at de samsvarer med strukturen til det sammenslåtte skjemaet.
Fordeler med Skjemasammenslåing
Skjemasammenslåing tilbyr flere overbevisende fordeler for organisasjoner som tar i bruk en mikrotjenestearkitektur:
- Enhetlig API: Gir et enkelt, konsistent API for klienter, noe som forenkler datatilgang og reduserer behovet for at klienter må samhandle direkte med flere tjenester. Dette resulterer i en renere og mer intuitiv utvikleropplevelse.
- Redusert klientkompleksitet: Klienter trenger bare å samhandle med det enhetlige skjemaet, noe som skjermer dem fra kompleksiteten i den underliggende mikrotjenestearkitekturen. Dette forenkler utviklingen på klientsiden og reduserer mengden kode som kreves på klienten.
- Økt skalerbarhet: Lar deg skalere individuelle tjenester uavhengig basert på deres spesifikke behov. Dette forbedrer den generelle skalerbarheten og robustheten til systemet. For eksempel kan en brukertjeneste som opplever høy belastning skaleres uten å påvirke andre tjenester som produktkatalogen.
- Forbedret vedlikeholdbarhet: Fremmer modularitet og separasjon av ansvarsområder, noe som gjør det enklere å vedlikeholde og utvikle individuelle tjenester. Endringer i én tjeneste har mindre sannsynlighet for å påvirke andre tjenester.
- Gradvis adopsjon: Kan implementeres trinnvis, slik at du gradvis kan migrere fra en monolittisk arkitektur til en mikrotjenestearkitektur. Du kan begynne med å slå sammen eksisterende API-er og deretter gradvis dekomponere monolitten til mindre tjenester.
Begrensninger med Skjemasammenslåing
Selv om Skjemasammenslåing gir mange fordeler, er det viktig å være klar over begrensningene:
- Kompleksitet: Implementering og administrasjon av skjemasammenslåing kan være komplekst, spesielt i store og komplekse systemer. Nøye planlegging og design er avgjørende.
- Ytelsesoverhead: Gatewayen introduserer noe ytelsesoverhead på grunn av det ekstra laget med indirekte kobling og behovet for å delegere spørringer og aggregere resultater. Nøye optimalisering er avgjørende for å minimere denne overheaden.
- Skjemakonflikter: Konflikter kan oppstå når man fletter skjemaer fra forskjellige tjenester, spesielt hvis de bruker de samme typenavnene eller feltnavnene. Dette krever nøye skjemadesign og potensielt omdøping av typer og felt.
- Begrensede avanserte funksjoner: Sammenlignet med Apollo Federation, mangler Skjemasammenslåing noen avanserte funksjoner som typeutvidelser og nøkkeldirektiver, noe som kan gjøre det mer utfordrende å håndtere relasjoner mellom typer på tvers av forskjellige skjemaer.
- Verktøymodenhet: Verktøyene og økosystemet rundt Skjemasammenslåing er ikke like modent som de rundt Apollo Federation. Dette kan gjøre det mer utfordrende å feilsøke og løse problemer.
Praktisk implementering av Skjemasammenslåing
La oss gå gjennom et forenklet eksempel på hvordan man implementerer Skjemasammenslåing ved hjelp av Node.js og graphql-tools
-biblioteket (et populært valg for skjemasammenslåing). Dette eksemplet involverer to mikrotjenester: en Brukertjeneste og en Produkttjeneste.
1. Definer de fjerntliggende skjemaene
Først definerer du GraphQL-skjemaene for hver av de fjerntliggende tjenestene.
Brukertjeneste (user-service.js
):
const { buildSchema } = require('graphql');
const userSchema = buildSchema(`
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
`);
const users = [
{ id: '1', name: 'Alice Smith', email: 'alice@example.com' },
{ id: '2', name: 'Bob Johnson', email: 'bob@example.com' },
];
const userRoot = {
user: (args) => users.find(user => user.id === args.id),
};
module.exports = {
schema: userSchema,
rootValue: userRoot,
};
Produkttjeneste (product-service.js
):
const { buildSchema } = require('graphql');
const productSchema = buildSchema(`
type Product {
id: ID!
name: String
price: Float
userId: ID! # Fremmednøkkel til Brukertjenesten
}
type Query {
product(id: ID!): Product
}
`);
const products = [
{ id: '101', name: 'Laptop', price: 1200, userId: '1' },
{ id: '102', name: 'Smartphone', price: 800, userId: '2' },
];
const productRoot = {
product: (args) => products.find(product => product.id === args.id),
};
module.exports = {
schema: productSchema,
rootValue: productRoot,
};
2. Opprett Gateway-tjenesten
Opprett nå gateway-tjenesten som skal slå de to skjemaene sammen.
Gateway-tjeneste (gateway.js
):
const { stitchSchemas } = require('@graphql-tools/stitch');
const { makeRemoteExecutableSchema } = require('@graphql-tools/wrap');
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const { introspectSchema } = require('@graphql-tools/wrap');
const { printSchema } = require('graphql');
const fetch = require('node-fetch');
async function createRemoteSchema(uri) {
const fetcher = async (params) => {
const response = await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
return response.json();
};
const schema = await introspectSchema(fetcher);
return makeRemoteExecutableSchema({
schema,
fetcher,
});
}
async function main() {
const userSchema = await createRemoteSchema('http://localhost:4001/graphql');
const productSchema = await createRemoteSchema('http://localhost:4002/graphql');
const stitchedSchema = stitchSchemas({
subschemas: [
{ schema: userSchema },
{ schema: productSchema },
],
typeDefs: `
extend type Product {
user: User
}
`,
resolvers: {
Product: {
user: {
selectionSet: `{ userId }`,
resolve(product, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: userSchema,
operation: 'query',
fieldName: 'user',
args: {
id: product.userId,
},
context,
info,
});
},
},
},
},
});
const app = express();
app.use('/graphql', graphqlHTTP({
schema: stitchedSchema,
graphiql: true,
}));
app.listen(4000, () => console.log('Gateway-server kjører på http://localhost:4000/graphql'));
}
main().catch(console.error);
3. Kjør tjenestene
Du må kjøre Brukertjenesten og Produkttjenesten på forskjellige porter. For eksempel:
Brukertjeneste (port 4001):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./user-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4001, () => console.log('Brukertjeneste kjører på http://localhost:4001/graphql'));
Produkttjeneste (port 4002):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, rootValue } = require('./product-service');
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootValue,
graphiql: true,
}));
app.listen(4002, () => console.log('Produkttjeneste kjører på http://localhost:4002/graphql'));
4. Spør det sammenslåtte skjemaet
Nå kan du spørre det sammenslåtte skjemaet gjennom gatewayen (som kjører på port 4000). Du kan kjøre en spørring som dette:
query {
product(id: "101") {
id
name
price
user {
id
name
email
}
}
}
Denne spørringen henter produktet med ID "101" og henter også den tilknyttede brukeren fra Brukertjenesten, noe som demonstrerer hvordan Skjemasammenslåing lar deg spørre etter data på tvers av flere tjenester i en enkelt forespørsel.
Avanserte teknikker for Skjemasammenslåing
Utover det grunnleggende eksemplet, er her noen avanserte teknikker som kan brukes til å forbedre implementeringen av Skjemasammenslåing:
- Skjemadelegering: Dette lar deg delegere deler av en spørring til forskjellige tjenester basert på dataene som etterspørres. For eksempel kan du delegere oppløsningen av en `User`-type til Brukertjenesten og oppløsningen av en `Product`-type til Produkttjenesten.
- Skjematransformasjon: Dette innebærer å modifisere skjemaet til en fjerntliggende tjeneste før det slås sammen i det enhetlige skjemaet. Dette kan være nyttig for å gi nye navn til typer og felt, legge til nye felt eller fjerne eksisterende felt.
- Egendefinerte resolvere: Du kan definere egendefinerte resolvere i gatewayen for å håndtere komplekse datatransformasjoner eller for å hente data fra flere tjenester og kombinere dem til ett enkelt resultat.
- Kontekstdeling: Det er ofte nødvendig å dele kontekstinformasjon mellom gatewayen og de fjerntliggende tjenestene, for eksempel autentiseringstokener eller bruker-ID-er. Dette kan oppnås ved å sende kontekstinformasjon som en del av spørringsdelegeringsprosessen.
- Feilhåndtering: Implementer robust feilhåndtering for å håndtere feil som oppstår i de fjerntliggende tjenestene på en elegant måte. Dette kan innebære logging av feil, retur av brukervennlige feilmeldinger eller forsøk på mislykkede forespørsler på nytt.
Valget mellom Skjemasammenslåing og Apollo Federation
Selv om Skjemasammenslåing er et levedyktig alternativ for GraphQL Føderasjon, har Apollo Federation blitt det mer populære valget på grunn av sine avanserte funksjoner og forbedrede utvikleropplevelse. Her er en sammenligning av de to tilnærmingene:
Funksjon | Skjemasammenslåing | Apollo Federation |
---|---|---|
Skjemadefinisjon | Bruker eksisterende GraphQL-skjemaspråk | Bruker et deklarativt skjemaspråk med direktiver |
Spørringsplanlegging | Krever manuell spørringsdelegering | Automatisk spørringsplanlegging av Apollo Gateway |
Typeutvidelser | Begrenset støtte | Innebygd støtte for typeutvidelser |
Nøkkeldirektiver | Ikke støttet | Bruker @key -direktivet for å identifisere entiteter |
Distribuert sporing | Krever manuell implementering | Innebygd støtte for distribuert sporing |
Verktøy og økosystem | Mindre modne verktøy | Mer modne verktøy og et stort fellesskap |
Kompleksitet | Kan være komplekst å administrere i store systemer | Designet for store og komplekse systemer |
Når bør man velge Skjemasammenslåing:
- Du har eksisterende GraphQL-tjenester og ønsker å kombinere dem raskt.
- Du trenger en enkel føderasjonsløsning og krever ikke avanserte funksjoner.
- Du har begrensede ressurser og ønsker å unngå overheaden med å sette opp Apollo Federation.
Når bør man velge Apollo Federation:
- Du bygger et stort og komplekst system med flere team og tjenester.
- Du trenger avanserte funksjoner som typeutvidelser, nøkkeldirektiver og distribuert sporing.
- Du ønsker en mer robust og skalerbar føderasjonsløsning.
- Du foretrekker en mer deklarativ og automatisert tilnærming til føderasjon.
Eksempler og bruksområder fra den virkelige verden
Her er noen eksempler fra den virkelige verden på hvordan GraphQL Føderasjon, inkludert Skjemasammenslåing, kan brukes:
- E-handelsplattform: En e-handelsplattform kan bruke GraphQL Føderasjon til å kombinere data fra flere tjenester, som en produktkatalogtjeneste, en brukertjeneste, en ordretjeneste og en betalingstjeneste. Dette lar klienter enkelt hente all informasjonen de trenger for å vise produktdetaljer, brukerprofiler, ordrehistorikk og betalingsinformasjon.
- Sosiale medier-plattform: En sosial medieplattform kan bruke GraphQL Føderasjon til å kombinere data fra tjenester som administrerer brukerprofiler, innlegg, kommentarer og 'likes'. Dette gjør det mulig for klienter å effektivt hente all informasjonen som kreves for å vise en brukers profil, deres innlegg, og kommentarene og 'likes' knyttet til disse innleggene.
- Finansielle tjenester-applikasjon: En applikasjon for finansielle tjenester kan bruke GraphQL Føderasjon til å kombinere data fra tjenester som administrerer kontoer, transaksjoner og investeringer. Dette lar klienter enkelt hente all informasjonen de trenger for å vise kontosaldoer, transaksjonshistorikk og investeringsporteføljer.
- Innholdsstyringssystem (CMS): Et CMS kan utnytte GraphQL Føderasjon for å integrere data fra ulike kilder som artikler, bilder, videoer og brukergenerert innhold. Dette gir et enhetlig API for å hente alt innhold relatert til et spesifikt emne eller en forfatter.
- Helseapplikasjon: Integrer pasientdata fra forskjellige systemer som elektroniske pasientjournaler (EPJ), laboratorieresultater og timebestilling. Dette gir leger ett enkelt tilgangspunkt til omfattende pasientinformasjon.
Beste praksis for Skjemasammenslåing
For å sikre en vellykket implementering av Skjemasammenslåing, følg disse beste praksisene:
- Planlegg skjemaet ditt nøye: Før du begynner å slå sammen skjemaer, planlegg strukturen til det enhetlige skjemaet nøye. Dette inkluderer å definere relasjonene mellom typer på tvers av forskjellige skjemaer, gi nye navn til typer og felt for å unngå konflikter, og vurdere de overordnede datatilgangsmønstrene.
- Bruk konsistente navnekonvensjoner: Ta i bruk konsistente navnekonvensjoner for typer, felt og operasjoner på tvers av alle tjenester. Dette vil bidra til å unngå konflikter og gjøre det lettere å forstå det enhetlige skjemaet.
- Dokumenter skjemaet ditt: Dokumenter det enhetlige skjemaet grundig, inkludert beskrivelser av typer, felt og operasjoner. Dette vil gjøre det lettere for utviklere å forstå og bruke skjemaet.
- Overvåk ytelse: Overvåk ytelsen til gatewayen og de fjerntliggende tjenestene for å identifisere og løse eventuelle ytelsesflaskehalser. Bruk verktøy som distribuert sporing for å spore forespørsler på tvers av flere tjenester.
- Implementer sikkerhet: Implementer passende sikkerhetstiltak for å beskytte gatewayen og de fjerntliggende tjenestene mot uautorisert tilgang. Dette kan innebære bruk av autentiserings- og autorisasjonsmekanismer, samt inputvalidering og output-koding.
- Versjoner skjemaet ditt: Etter hvert som du utvikler skjemaene dine, versjoner dem på en hensiktsmessig måte for å sikre at klienter kan fortsette å bruke eldre versjoner av skjemaet uten at noe går i stykker. Dette vil bidra til å unngå ødeleggende endringer og sikre bakoverkompatibilitet.
- Automatiser distribusjon: Automatiser distribusjonen av gatewayen og de fjerntliggende tjenestene for å sikre at endringer kan distribueres raskt og pålitelig. Dette vil bidra til å redusere risikoen for feil og forbedre den generelle smidigheten i systemet.
Konklusjon
GraphQL Føderasjon med Skjemasammenslåing tilbyr en kraftig tilnærming til å bygge enhetlige API-er fra flere tjenester i en mikrotjenestearkitektur. Ved å forstå kjernekonseptene, fordelene, begrensningene og implementeringsteknikkene, kan du utnytte Skjemasammenslåing for å forenkle datatilgang, forbedre skalerbarhet og øke vedlikeholdbarheten. Selv om Apollo Federation har blitt en mer avansert løsning, forblir Skjemasammenslåing et levedyktig alternativ for enklere scenarier eller ved integrering av eksisterende GraphQL-tjenester. Vurder nøye dine spesifikke behov og krav for å velge den beste tilnærmingen for din organisasjon.